package com.kaisu.blog.web.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kaisu.blog.application.user.service.JWTService;
import com.kaisu.blog.domain.user.User;
import com.kaisu.blog.domain.user.repository.UserRepository;
import com.kaisu.blog.web.result.Result;
import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;


/**
 * @author kaisu
 */
@Slf4j
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    private final UserRepository userRepository;
    private final JWTService jwtService;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager, UserRepository userRepository, JWTService jwtService) {
        super(authenticationManager);
        this.userRepository = userRepository;
        this.jwtService = jwtService;
    }


    @SneakyThrows
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
        String token = jwtService.getToken(request);
        // 如果请求头中没有Authorization信息则直接放行了
        if (!StringUtils.hasLength(token)) {
            chain.doFilter(request, response);
            return;
        }
        // 如果请求头中有token，则进行解析，并且设置认证信息
        String id = jwtService.validateToken(token);
        if (!StringUtils.hasLength(id)) {
            log.error("从token中未获取到用户id, token：{}, URI：{}", token, request.getServletPath());
            chain.doFilter(request, response);
            return;
        }
        //从缓存中验证token的存在性
        User user;
        try {
            user = userRepository.findById(id);
        } catch (UsernameNotFoundException e) {
            response.setContentType("application/json;charset=UTF-8");
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.getWriter().write(new ObjectMapper().writeValueAsString(Result.fail("token不存在或错误！")));
            response.getWriter().flush();
            return;
        }
        // 如果从持久化存储中仍未查到，则执行后续操作，最后返回用户不存在信息到前端
        if (null != user) {
            // 清空“密码”属性
            // 创建验证通过的令牌对象
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
            // 设置令牌到安全上下文中
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }
        chain.doFilter(request, response);
    }
}